package org.tlang.parser;

import org.tlang.ast.AST;
import org.tlang.ast.list.array.ArrayAccessor;
import org.tlang.ast.list.array.ArrayLiteral;
import org.tlang.ast.list.array.NewArrayInvoker;
import org.tlang.exception.ParseException;
import org.tlang.keywords.KeyWords;
import org.tlang.lexer.Lexer;
import org.tlang.lexer.token.Token;

import java.util.ArrayList;
import java.util.List;

public class ArrayParser extends ExprParser {

    public ArrayParser(Lexer lexer) {
        super(lexer);
    }

    /**
     * array_literal: "[" [ expr { "," expr } ] "]"
     */
    protected AST arrayLiteral() throws ParseException {
        skip("[");
        List<AST> result = new ArrayList<>();
        while (true) {
            if (isIdentifier("]")) {
                skip("]");
                return new ArrayLiteral(result);
            }

            if (result.isEmpty()) {
                result.add(expr());
            } else {
                skip(",");
                result.add(expr());
            }
        }
    }

    /**
     * example: [1][2][3]
     * array_postfix: { "[" expr "]" }
     */
    private List<AST> arrayPostfix() throws ParseException {
        List<AST> result = new ArrayList<>();
        while (isIdentifier("[")) {
            skip("[");
            result.add(expr());
            skip("]");
        }
        return result;
    }

    /**
     * factor: "new" identifier array_postfix | super_factor
     */
    @Override
    protected AST factor() throws ParseException {
        Token token0 = lexer.peek(0);
        Token token1 = lexer.peek(1);
        Token token2 = lexer.peek(2);

        if (token0.isIdentifier() && token1.isIdentifier() && token2.isIdentifier()
                && KeyWords.NEW.equals(token0.getText()) && "[".equals(token2.getText())) {
            skip(KeyWords.NEW);
            List<AST> result = new ArrayList<>();
            result.add(identifier());
            result.addAll(arrayPostfix());
            return new NewArrayInvoker(result);
        }

        return super.factor();
    }

    /**
     * 扩展primary，支持解析数据访问语句
     * example: a[1][2]
     * primary: super_primary { "[" expr "]" } | array_literal
     */
    @Override
    protected AST primary() throws ParseException {
        if (isIdentifier("[")) {
            return arrayLiteral();
        }

        AST primary = super.primary();

        List<AST> arrayPostfix = arrayPostfix();

        if (!arrayPostfix.isEmpty()) {
            arrayPostfix.add(0, primary);
            return new ArrayAccessor(arrayPostfix);
        } else {
            return primary;
        }
    }
}
